/**
 * @author qiuny
 * @description 核心插件，包含基础方法，用于操作fabric
 * @class
 * @see {@link CoverEditor}
 */

import { SelectEvent, SelectMode } from "@/scripts/eventType";
import { fabric } from "fabric";
import { downloadFile, chooseFileByType } from "../utils";
import { v4 as uuidV4 } from "uuid";

class ServePlugin {
    static apis = [
        "insertFile",
        "loadJSON",
        "getJson",
        "dragAddItem",
        "clipboard",
        "clipboardBase64",
        "saveJson",
        "saveSvg",
        "saveImg",
        "clear",
        "preview",
        "addImgByElement",
        "getImageExtension",
        "getSelectMode",
    ];
    static events = [SelectEvent.ONE, SelectEvent.MULTI, SelectEvent.CANCEL];
    constructor(canvas, editor) {
        this.canvas = canvas;
        this.editor = editor;
        this.selectedMode = SelectMode.EMPTY;
        this._initSelectionEvent();
    }

    _initSelectionEvent() {
        this.canvas.on("selection:created", () => this._emitSelectEvent());
        this.canvas.on("selection:updated", () => this._emitSelectEvent());
        this.canvas.on("selection:cleared", () => this._emitSelectEvent());
    }

    // 清理|创建|更新元素时触发
    _emitSelectEvent() {
        const canvas = this.canvas;
        if (!canvas) {
            throw TypeError("fabric还没有初始化完成");
        }
        // console.log(canvas.getActiveObjects(), this.editor, 'ServePlugin');
        // const actives = canvas.getActiveObjects().filter(item => !item instanceof fabric.GuideLine)
        const actives = canvas.getActiveObjects();
        // 设置选择模式和广播事件
        if (actives && actives.length === 1) {
            this.selectedMode = SelectEvent.ONE;
            this.editor.emit(SelectEvent.ONE, actives);
        } else if (actives && actives.length > 1) {
            this.selectedMode = SelectMode.MULTI;
            this.editor.emit(SelectEvent.MULTI, actives);
        } else {
            this.selectedMode = SelectMode.EMPTY;
            this.editor.emit(SelectEvent.CANCEL, actives);
        }
    }

    async insertFile (callback = function () {}) {
        await chooseFileByType({
            accept: '.json',
            multiple: false
        }).then(files => {
            if (files && files.length > 0) {
                const file = files[0]
                const reader = new FileReader()
                reader.readAsText(file, 'UTF-8')
                reader.onload = () => {
                    this.loadJSON(reader.result, callback)
                }
            }
        })
    }

    loadJSON (jsonFile, callback) {
        const temp = typeof jsonFile === 'string'?JSON.parse(jsonFile):jsonFile
        const textPaths = []
        temp.objects.forEach(item => {
            // 确保导入元素ID不能为空
            !item.id && (item.id=uuidV4())
            if (temp.type ==='i-text' && item.path) {
                textPaths.push({ id: item.id, path: item.path })
                item.path = null;
            }
        })
        // 将json对象重新转化为json字符串
        jsonFile = JSON.stringify(temp)
        // 调用导入前钩子
        this.editor.hooksEntity.hookImportBefore.callAsync(jsonFile, () => {
            this.canvas.loadFromJSON(jsonFile, () => {
                // 把i-text对应的path加上
                this.renderITextPath(textPaths)
                this.canvas.renderAll()

                // 调用加载后钩子
                this.editor.hooksEntity.hookImportAfter.callAsync(jsonFile, () => {
                    this.canvas.renderAll()
                    callback&&callback()
                    // 导入完成，广播事件
                    this.editor.emit('loadJSON')
                })
            })
        })
    }

    renderITextPath (textPaths = []) {
        textPaths.forEach(item => {
            const object = this.canvas.getObjects().find(el => el.id === item.id)
            if (object) {
                fabric.Path.fromObject(item.path, e => {
                    object.set('path', e)
                })
            }
        })
    }

    getSaveSvgOption() {
        const workspace = this.canvas.getObjects().find((item) => item.id === "workspace");
        if (!workspace) {
            throw new Error("workspace does not exist! please check.");
        }
        return {
            width: workspace.width,
            height: workspace.height,
            viewBox: {
                x: workspace.left,
                y: workspace.top,
                width: workspace.width,
                height: workspace.height,
            },
        };
    }

    getSaveOption() {
        const workspace = this.canvas.getObjects().find((item) => item.id === "workspace");
        const { left, top, width, height } = workspace;
        const option = {
            name: "New Image",
            format: "png",
            quality: 1,
            width,
            height,
            left,
            top,
        };
        return option;
    }

    saveSvg() {
        // 调用异步方法
        this.editor.hooksEntity.hookSaveBefore.callAsync("", () => {
            const option = this.getSaveSvgOption();
            const svgObject = this.canvas.toSVG(option);
            const fileStr = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgObject)}`;
            this.editor.hooksEntity.hookSaveAfter.callAsync(fileStr, () => {
                downloadFile(fileStr, "svg");
            });
        });
    }

    saveImg() {
        this.editor.hooksEntity.hookSaveBefore.callAsync("", () => {
            const option = this.getSaveOption();
            this.canvas.setViewportTransform([1, 0, 0, 1, 0, 0]);
            const dataUrl = this.canvas.toDataURL(option);
            this.editor.hooksEntity.hookSaveAfter.callAsync(dataUrl, () => {
                downloadFile(dataUrl, "png");
            });
        });
    }

    saveJson () {
        const jsonUrl = this.getJson()
        const fileStr = `data:text/json;charset=utf-8,${encodeURIComponent(JSON.stringify(jsonUrl))}`
        downloadFile(fileStr, 'json')
        console.log('saveJson');
    }

    getJson() {
        return this.canvas.toJSON(["id", "gradientAngle", "selectable", "hasControls", "linkData"]);
    }

    clear() {
        this.canvas.getObjects().forEach((obj) => {
            if (obj.id !== "workspace") {
                this.canvas.remove(obj);
            }
        });

        this.canvas.discardActiveObject();
        this.canvas.renderAll();

        // 通知撤回和重做的按钮置灰
        // this.editor.emit("historyUpdate", 0, 0);
    }

    getSelectMode() {
        return String(this.selectedMode);
    }

    destroy() {
        console.log("ServePlugin destroy");
    }
}

export default ServePlugin;
